package com.zorzhi.automation.service;

import cn.hutool.core.util.StrUtil;
import com.zorzhi.automation.entity.MergeEntity;
import com.zorzhi.automation.entity.R;
import com.zorzhi.automation.utils.MergeUtil;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author zorzhi
 * @Date 2025/4/4 13:13
 */
@Service
public class MergeService {

    /**
     * 获取分支列表
     *
     * @return R
     */
    public R getBranches(MergeEntity mergeEntity) {

        String gitUrl = mergeEntity.getGitUrl();
        String account = mergeEntity.getGitAccount();
        String password = mergeEntity.getGitPassword();

        try {
            LsRemoteCommand lsRemoteCommand = Git.lsRemoteRepository()
                    .setHeads(true)
                    .setRemote(gitUrl)
                    .setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
            Collection<Ref> branches = lsRemoteCommand.call();
            Map<String, String> branchNames = new HashMap<>();
            for (Ref branch : branches) {
                if (!branch.getName().contains("master")) {
                    String branchName = branch.getName().replace("refs/heads/", "");
                    branchNames.put(branchName, branchName);
                    // System.err.println(branchName);
                }
            }
            System.err.println("获取分支成功，共" + branchNames.size() + "个");
            return R.success(branchNames);
        } catch (GitAPIException e) {
            e.printStackTrace();
            return R.failure("Failed to retrieve branches: " + e.getMessage());
        }
    }


    /**
     * 将主干代码 合并 到 分支上
     *
     * @return R
     */
    public R merge(MergeEntity mergeEntity) {
        String gitUrl = mergeEntity.getGitUrl();
        String account = mergeEntity.getGitAccount();
        String password = mergeEntity.getGitPassword();
        String branchPath = mergeEntity.getBranchName();
        String deploymentPackagePath = mergeEntity.getDeploymentPath();
        String projectPath = mergeEntity.getProjectPath();
        String pcProjectName = mergeEntity.getPcProjectName();

        System.err.println(">>>>>> merge start <<<<<<\n");

        try (Git git = Git.open(new File(projectPath))) {
            UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(account, password);
            // 【1】、切换到 master 分支并更新代码
            git.checkout().setName("master").call();
            try {
                //git.pull().setCredentialsProvider(credentialsProvider).call();
                PullResult pullResult = git.pull().setCredentialsProvider(credentialsProvider).call();
                if (pullResult.isSuccessful()) {
                    System.out.println("Pull master successful, updated to commit: " + pullResult.getMergeResult().getNewHead().getName());
                }
            } catch (Exception e) {
                // 回滚代码到 最近一次 提交后的 状态（若本地和仓库中都修改了同样的文件，更新冲突报错后，执行下面语句，会将本地修改后的代码回滚到仓库最后一次提交后的状态）
                //git.reset().setMode(org.eclipse.jgit.api.ResetCommand.ResetType.HARD).call();
                e.printStackTrace();
                return R.failure("主干更新代码异常：" + e.getMessage());
            }

            String branchName = branchPath.replace("refs/heads/", ""); // 分支名称。移除前缀

            // 【2】、切换到目标分支并更新代码
            // 【2.1】、检查分支是否存在 本地仓库
            List<Ref> refList = git.branchList().call();
            boolean branchExists = refList.stream().anyMatch(ref -> {
//                System.err.println(ref.getName());
                String refName = ref.getName().replace("refs/heads/", "");
                return refName.equals(branchName);
            });

            if (!branchExists) {
                try {
                    // 进行 fetch 操作。从远程仓库拉取最新的分支和提交信息
                    git.fetch().setRemote(gitUrl).setCredentialsProvider(credentialsProvider).call();

                    // 使用 setListMode(ListBranchCommand.ListMode.REMOTE) 只列出远程分支。并检查远程分支列表是否存在指定分支
                    boolean remoteBranchExists = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call().stream()
                            .anyMatch(ref -> {
                                String refName = ref.getName().replace("refs/heads/", "");
                                return refName.equals(branchName);
                            });

                    if (!remoteBranchExists) {
                        return R.failure("分支 " + branchName + " 不存在");
                    }
                    System.out.println("Fetch 成功！");
                } catch (TransportException e) {
                    if (e.getMessage().contains("Nothing to fetch")) {
                        System.out.println("远程仓库【" + branchName + "】无新内容，无需拉取。");
                    } else {
                        System.err.println("Fetch 失败: " + e.getMessage());
                        e.printStackTrace();
                    }
                } catch (Exception e) {
                    System.err.println("Git 操作失败: " + e.getMessage());
                    e.printStackTrace();
                }
            }

            // 【2.2】、切换到目标分支
            Ref branchRef = git.checkout()
                    .setName(branchName)
                    .setCreateBranch(!branchExists) // 如果本地分支不存在，则创建
                    .setStartPoint("origin/" + branchName)
                    .call();

            // 【2.3】、更新分支代码
            try {
                PullResult pullResult = git.pull().setCredentialsProvider(credentialsProvider).call();
                if (pullResult.isSuccessful()) {
                    System.out.println("Pull " + branchName + " successful, updated to commit: " + pullResult.getMergeResult().getNewHead().getName());
                }
            } catch (Exception e) {
                git.reset().setMode(ResetCommand.ResetType.HARD).call();
                e.printStackTrace();
                return R.failure("分支更新代码异常：" + e.getMessage());
            }

            // 【3】、获取主干相对于分支的新提交记录、获取分支最后一次提交日期
            // 【3.1】、获取主干相对于分支的新提交记录
            Iterable<RevCommit> commits = git.log().addRange(git.getRepository().resolve(branchName), git.getRepository().resolve("master")).call();
            StringBuilder mergeCommitMessages = new StringBuilder();
            for (RevCommit commit : commits) {
                mergeCommitMessages.append(commit.getFullMessage());
            }
            System.out.println(branchName + "分支合并提交记录: \n" + mergeCommitMessages);

            if (mergeCommitMessages.length() < 1) {
                return R.failure(901, "无新增代码，无需合并");
            }

            // 【3.2】、获取分支最后一次提交日期
            String latestCommitDate = null;
            try (RevWalk revWalk = new RevWalk(git.getRepository())) {
                // 获取分支最后提交日期
                ObjectId objectId = git.getRepository().resolve("refs/remotes/origin/" + branchName);
                RevCommit latestCommit = revWalk.parseCommit(objectId);
                int commitTime = latestCommit.getCommitTime();// 返回提交时间戳
                latestCommitDate = MergeUtil.IntTimestampToDate(commitTime);
                System.err.println("【" + branchName + "】分支最后提交objectId：" + objectId);
                System.err.println("【" + branchName + "】分支最后提交时间：" + latestCommitDate + "\n");
            } catch (Exception e) {
                e.printStackTrace();
                return R.failure("根据分支最后一次提交日期异常：" + e.getMessage());
            }

            // 【4】合并 master 代码 到 目标分支（master -> 分支）
            try {
                // 合并 master 分支到目标分支
                git.merge().include(git.getRepository().resolve("master")).call();
            } catch (Exception e) {
                e.printStackTrace();
                git.reset().setMode(org.eclipse.jgit.api.ResetCommand.ResetType.HARD).call();
                return R.failure("分支合并代码有异常：" + e.getMessage());
            }

            // 【5】、推送分支代码
            try {
                git.push().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
            } catch (Exception e) {
                e.printStackTrace();
                git.reset().setMode(org.eclipse.jgit.api.ResetCommand.ResetType.HARD).call();
                return R.failure("推送分支代码失败: " + e.getMessage());
            }

            // 【6】、创建文件夹
            File folder = new File(deploymentPackagePath, branchName);
            if (!folder.exists()) {
                folder.mkdirs();
            }

            // 【7】、创建子文件夹，名称为当前时间
            String timestamp = new SimpleDateFormat("yyyy-MM-dd_HHmmss").format(new Date());
            File timestampFolder = new File(folder, timestamp);
            if (!timestampFolder.exists()) {
                timestampFolder.mkdirs();
            }

            // 【8】、 在日期文件夹中新建一个 update.txt 文件，文件内容是主干合并到分支时的提交记录
            File updateFile = new File(timestampFolder, "升级记录.txt");
            try {
                String updateContent = "Merge commit messages:\n" + mergeCommitMessages;
                Files.write(updateFile.toPath(), updateContent.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
                return R.failure("创建 update.txt 文件失败: " + e.getMessage());
            }

            // 【9】、将创建的 日期 子文件夹路径 返回给调用者，用于 后续操作(maven打包。将打包好的文件复制到此文件夹下)
            String path = timestampFolder.getPath();

            System.err.println("-----------------代码合并成功------------------");
            Map<String, String> resultMap = new HashMap<>();
            resultMap.put("path", path);
            resultMap.put("latestCommitDate", latestCommitDate);
            return R.success(resultMap, "合并成功");
//            return R.success("合并成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.failure("合并失败: " + e.getMessage());
        }
    }


    /**
     * maven 打包（打包成功后，将jar 迁移到 指定目录下）
     *
     * @param projectPath PC后台项目路径
     * @param outputPath  输出目录路径
     */
    public R mavenPackage(String projectPath, String outputPath) {
        if (StrUtil.isEmpty(projectPath) || StrUtil.isEmpty(outputPath)) {
            return R.failure(900, "jar 项目路径或输出路径为空，不进行打包");
        }
        System.err.println("\n>>>>>> maven package start <<<<<<\n");

        // 动态获取 Maven 可执行文件路径
//        String mavenExecutablePath = MergeUtil.getMavenExecutablePath();
//        if (mavenExecutablePath == null) {
//            return R.failure("无法找到 Maven 可执行文件，请确保已正确安装 Maven 并配置环境变量。");
//        }
        String mavenExecutablePath = MergeUtil.isWindows() ? "mvn.cmd" : "mvn";

        String command = mavenExecutablePath + " clean package -DskipTests";

        try {
            Process process = Runtime.getRuntime().exec(command, null, new File(projectPath));

            // 异步读取子进程的输出和错误流
            // 加日志输出目的：因为 process.waitFor() 方法阻塞了主线程，导致程序无法继续执行。为了避免这种情况，我们可以使用异步方式来处理子进程的输出和错误流，从而避免主线程被阻塞。
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GB2312"))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "GB2312"))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.err.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("Maven 打包成功");

                // 新增逻辑：将打包好的 JAR 文件复制到指定目录下
                File targetDir = new File(outputPath, "api");
                if (!targetDir.exists()) {
                    targetDir.mkdirs();
                }

                // 动态获取生成的 JAR 文件路径
                File targetFolder = new File(projectPath, "target");
                File[] jarFiles = targetFolder.listFiles((dir, name) -> name.endsWith(".jar") && !name.endsWith("-sources.jar") && !name.endsWith("-javadoc.jar"));
                if (jarFiles == null || jarFiles.length == 0) {
                    return R.failure("未找到生成的 JAR 文件，请检查 Maven 打包配置。");
                }

                // 假设只生成了一个 JAR 文件
                File jarFile = jarFiles[0];

                // 复制 JAR 文件到目标目录
                File destinationFile = new File(targetDir, jarFile.getName());
                Files.copy(jarFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                System.err.println("maven 打包完成，JAR 文件已成功复制到目标目录 ——> " + destinationFile.getAbsolutePath());

            } else {
                System.err.println("Maven 打包失败，退出码：" + exitCode);
                return R.failure("Maven 打包失败，退出码：" + exitCode);
            }
        } catch (Exception e) {
            System.err.println("执行 Maven 打包时发生错误：" + e.getMessage());
            e.printStackTrace();
            return R.failure("执行 Maven 打包时发生错误：" + e.getMessage());
        }
        return R.success("maven 打包成功");
    }


    /**
     * Vue 项目打包（打包成功后，将 dist 目录剪切到指定目录下）
     *
     * @param projectPath vue项目路径
     * @param outputPath  输出目录路径
     */
    public R vuePackage(String projectPath, String outputPath) {
        if (StrUtil.isEmpty(projectPath) || StrUtil.isEmpty(outputPath)) {
            return R.failure(900, "vue 项目路径或输出路径为空，不进行打包");
        }
        System.err.println("\n>>>>>> vue package start <<<<<<\n");

        // 动态获取 npm 可执行文件路径
//        String npmExecutablePath = MergeUtil.getNpmExecutablePath();
        String npmExecutablePath = "";
        MergeEntity mergeFileContent = (MergeEntity) MergeUtil.getMergeFileContent().getData();
        String npmExecutableConfigPath = mergeFileContent.getNpmExecutablePath();
        if (StrUtil.isNotBlank(npmExecutableConfigPath)) {
            npmExecutablePath = npmExecutableConfigPath;
        } else {
            npmExecutablePath = MergeUtil.isWindows() ? "npm.cmd" : "npm";
        }
        if (npmExecutablePath == null) {
            return R.failure("无法找到 npm 可执行文件，请确保已正确安装 Node.js 并配置环境变量。");
        }

        try {
            // 先执行 npm install
            String installCommand = npmExecutablePath + " install";
            Process installProcess = Runtime.getRuntime().exec(installCommand, null, new File(projectPath));
            int installExitCode = installProcess.waitFor();

            if (installExitCode != 0) {
                return R.failure("npm install 执行失败，退出码: " + installExitCode);
            }

            // 然后执行 npm run build
            String buildCommand = npmExecutablePath + " run build";
            Process process = Runtime.getRuntime().exec(buildCommand, null, new File(projectPath));
            
            // 异步读取子进程的输出和错误流
            // 加日志输出目的：因为 process.waitFor() 方法阻塞了主线程，导致程序无法继续执行。为了避免这种情况，我们可以使用异步方式来处理子进程的输出和错误流，从而避免主线程被阻塞。
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GB2312"))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "GB2312"))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.err.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("Vue 打包成功");

                // 动态获取生成的 dist 目录路径
                File distDir = new File(projectPath, "dist");
                if (!distDir.exists() || !distDir.isDirectory()) {
                    return R.failure("未找到生成的 dist 目录，请检查 Vue 打包配置。");
                }
                File targetDir = new File(outputPath);
                if (!targetDir.exists()) {
                    targetDir.mkdirs();
                }

                // 删除目标目录，已存在的 dist
                File destinationDir = new File(targetDir, "dist");
                if (destinationDir.exists()) {
                    MergeUtil.deleteDirectory(destinationDir);
                }

                // 移动 dist 目录到目标路径
//                Files.move(distDir.toPath(), destinationDir.toPath(), StandardCopyOption.REPLACE_EXISTING);
                MergeUtil.copyDirectoryRecursively(distDir.toPath(), destinationDir.toPath());
                System.err.println("vue 打包完成，dist 目录已成功复制到目标目录 ——> " + destinationDir.getAbsolutePath());
            } else {
                System.err.println("Vue 打包失败，退出码：" + exitCode);
                return R.failure("Vue 打包失败，退出码：" + exitCode);
            }
        } catch (Exception e) {
            System.err.println("执行 Vue 打包时发生错误：" + e.getMessage());
            e.printStackTrace();
            return R.failure("执行 Vue 打包时发生错误：" + e.getMessage());
        }
        return R.success("Vue 打包成功");
    }


    /**
     * 实现 uniapp 项目的打包，并将打包文件迁移到指定目录
     *
     * @param projectPath uniapp 项目路径
     * @param outputPath  输出目录路径
     */
    public R uniAppPackage(String projectPath, String outputPath) {
        if (StrUtil.isEmpty(projectPath) || StrUtil.isEmpty(outputPath)) {
            return R.failure(900, "uniapp 项目路径或输出路径为空，不进行打包");
        }
        System.err.println("\n>>>>>> uniapp package start <<<<<<\n");

        try {
            // 1. 动态获取 HBuilderX 的 cli.exe 路径
            String hbuilderXDir = System.getenv("HBuilderX_HOME"); // 从环境变量中获取 HBuilderX 安装路径
            if (hbuilderXDir == null || hbuilderXDir.isEmpty()) {
                hbuilderXDir = "C:\\Program Files\\DCloud\\HBuilderX"; // 默认路径
            }

            // 通过cli.exe 进行打包，前提：启动HBuilderX
//            Path cliPath = Paths.get(hbuilderXDir, "cli.exe");
//            if (!Files.exists(cliPath)) {
//                String msg = "请检查HBuilderX安装路径或环境变量配置【环境变量key为HBuilderX_HOME，值为HBuilderX安装路径】。";
//                return R.failure(msg);
//            }
//            // 2. 切换到 uniapp 项目目录并执行打包命令
//            ProcessBuilder processBuilder = new ProcessBuilder(cliPath.toString(), "publish", "--platform", "h5", "--project", projectPath);
//            processBuilder.directory(new File(projectPath));
//            Process process = processBuilder.start();

            // 下面方式 其实 执行命令是："%HBuilderX_HOME%\\plugins\\uniapp-cli\" && cross-env NODE_ENV=production UNI_PLATFORM=h5 UNI_INPUT_DIR=\"%cd%\" UNI_OUTPUT_DIR=\"%cd%\\unpackage\\dist\\build\\h5\" \"%HBuilderX_HOME%\\plugins\\node\\node.exe\"  \"%HBuilderX_HOME%\\plugins\\uniapp-cli\\bin\\uniapp-cli.js"
            // 动态获取 npm 可执行文件路径
//            String npmExecutablePath = MergeUtil.getNpmExecutablePath();
            String npmExecutablePath;
            MergeEntity mergeFileContent = (MergeEntity) MergeUtil.getMergeFileContent().getData();
            String npmExecutableConfigPath = mergeFileContent.getNpmExecutablePath();
            if (StrUtil.isNotBlank(npmExecutableConfigPath)) {
                npmExecutablePath = npmExecutableConfigPath;
            } else {
                npmExecutablePath = MergeUtil.isWindows() ? "npm.cmd" : "npm";
            }
            if (npmExecutablePath == null) {
                return R.failure("无法找到 npm 可执行文件，请确保已正确安装 Node.js 并配置环境变量。");
            }

            // 先执行 npm install
            String installCommand = npmExecutablePath + " install";
            Process installProcess = Runtime.getRuntime().exec(installCommand, null, new File(projectPath));
            int installExitCode = installProcess.waitFor();

            if (installExitCode != 0) {
                return R.failure("npm install 执行失败，退出码: " + installExitCode);
            }


            String command = npmExecutablePath + " run build:h5";

            // 2. 切换到 uniapp 项目目录并执行打包命令
            Process process = Runtime.getRuntime().exec(command, null, new File(projectPath));

            // 异步读取子进程的输出和错误流
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.err.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            int exitCode = process.waitFor();
            if (exitCode != 0) {
                return R.failure("uniapp 打包失败，退出码：" + exitCode);
            }

            // 3. 获取打包生成的文件路径
            Path sourceDir = Paths.get(projectPath, "unpackage", "dist", "build", "web");
            if (!Files.exists(sourceDir)) {
                return R.failure("未找到 uniapp 打包生成的文件目录：" + sourceDir);
            }

            // 4. 创建输出目录（如果不存在）
            Path targetDir = Paths.get(outputPath, "web");
            Files.createDirectories(targetDir);

            // 5. 复制打包文件到指定目录
            MergeUtil.copyDirectoryRecursively(sourceDir, targetDir);
            System.err.println("uniapp 打包完成，web 目录已成功复制到目标目录 ——> " + targetDir);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            return R.failure("uniapp 打包或文件迁移失败" + e.getMessage());
        }
        return R.success("uniapp 打包成功");
    }


    /**
     * 切换分支
     */
    public R switchBranch(MergeEntity mergeEntity) {
        String account = mergeEntity.getGitAccount();
        String password = mergeEntity.getGitPassword();
        String projectPath = mergeEntity.getProjectPath();
        String branchName = mergeEntity.getBranchName();
        System.err.println(">>>>>> switch branch 【" + branchName + "】 start <<<<<<\n");

        branchName = branchName.replace("refs/heads/", ""); // 分支名称。移除前缀
        if (StrUtil.isEmpty(branchName)) {
            return R.failure(900, "分支名称为空，不进行切换");
        }

        try (Git git = Git.open(new File(projectPath))) {

            UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(account, password);

            // 【1】、切换到 master 分支并更新代码
            if ("master".equals(branchName)) {
                git.checkout().setName("master").call();
                try {
                    git.pull().setCredentialsProvider(credentialsProvider).call();
//                    git.pull().call();
                } catch (Exception e) {
                    // 回滚代码到 最近一次 提交后的 状态（若本地和仓库中都修改了同样的文件，更新冲突报错后，执行下面语句，会将本地修改后的代码回滚到仓库最后一次提交后的状态）
                    //git.reset().setMode(org.eclipse.jgit.api.ResetCommand.ResetType.HARD).call();
                    e.printStackTrace();
                    return R.failure("主干更新代码有异常：" + e.getMessage());
                }
            } else {
                // 【2】、切换到目标分支并更新代码
                // 【2.1】、检查分支是否存在 本地仓库
                String finalBranchName = branchName;
                boolean branchExists = git.branchList().call().stream()
                        .anyMatch(ref -> ref.getName().endsWith(finalBranchName));

                if (!branchExists) {
                    // 检查分支是否存在 远程仓库。尝试从远程仓库获取分支
                    git.fetch().setRemote("origin").call();
                    boolean remoteBranchExists = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call().stream()
                            .anyMatch(ref -> ref.getName().endsWith(finalBranchName));

                    if (!remoteBranchExists) {
                        return R.failure("分支 " + branchName + " 不存在");
                    }
                }

                // 【2.2】、切换到目标分支
                git.checkout()
                        .setName(branchName)
                        .setCreateBranch(!branchExists) // 如果本地分支不存在，则创建
                        .setStartPoint("origin/" + branchName)
                        .call();

                // 【2.3】、更新分支代码
                try {
                    git.pull().setCredentialsProvider(credentialsProvider).call();
                } catch (Exception e) {
                    e.printStackTrace();
                    return R.failure("分支更新代码有异常：" + e.getMessage());
                }
            }

            return R.success("切换[" + branchName + "]分支成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.failure("切换[" + branchName + "]分支失败: " + e.getMessage());
        }
    }

}
